/**************************************************************************
 * graph.c
 *
 * CECS619 Project 3
 *
 * Authors: Max Stoler, Jason Hatton
 *
 *************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "graph.h"

/**************************************************************************
 * GraphLoad
 *
 * Load a graph from a file. Returns null if unsuccessful
**************************************************************************/
Graph *GraphLoad(const char *fileName)
{
	char buffer[128];
	FILE *file;
	Graph *g;
	int numEdges;
	int i;
	int len;
	int p,q;

	g = (Graph*)malloc(sizeof(Graph));
	if(!g)
	{
		fprintf(stderr, "Out of memory!\n");
		exit(1);
	}
	
	file = fopen(fileName, "r");
	if(!file)
	{
		perror("Failed to open file");
		return NULL;
	}

	if( fgets(buffer, sizeof(buffer), file) == NULL)
	{
		fprintf(stderr, "Failed to read vetex count\n");
		return NULL;
	}
	
	sscanf(buffer, "%d", &g->size);

	g->graph = (int*)malloc(g->size*g->size*sizeof(int));
	if(!g->graph)
	{
		fprintf(stderr, "Out of memory!\n");
		exit(1);
	}
	memset(g->graph, 0, g->size*g->size*sizeof(int));

	g->vertexNames = (char**)malloc(g->size*sizeof(char*));
	if(!g->vertexNames)
	{
		fprintf(stderr, "Out of memory!\n");
		exit(1);
	}

	if( fgets(buffer, sizeof(buffer), file) == 0)
	{
		fprintf(stderr, "Failed to read edge count!\n");
		return NULL;
	}

	sscanf(buffer, "%d", &numEdges);

	for(i=0; i<g->size; i++)
	{
		if( fgets(buffer, sizeof(buffer), file) == 0)
		{
			fprintf(stderr, "Failed to read vertex name!\n");
			return NULL;
		}
		len = strlen(buffer);
		len--;
		buffer[len] = '\0';
		g->vertexNames[i] = (char*)malloc((len+1)*sizeof(char));
		if(!g->vertexNames[i])
		{
			fprintf(stderr, "Out of memory.\n");
			exit(1);
		}
		strcpy(g->vertexNames[i], buffer);
	}

	for(i=0; i<numEdges; i++)
	{
		if( fgets(buffer, sizeof(buffer), file) == 0)
		{
			fprintf(stderr, "Failed to read edge!\n");
			return NULL;
		}
		sscanf(buffer, "%d %d", &p, &q);
		GraphSetAdj(g, p, q, 1);
		GraphSetAdj(g, q, p, 1);
		/*GraphAdj(g, p, q) = 1;*/
	}

	fclose(file);
	return g;
}


/**************************************************************************
 * GraphCopy
 *
 * Copies a graph. Note that the vertex names are not copyed.
**************************************************************************/
Graph *GraphCopy(Graph *g)
{
	Graph *g2 = 0;
	g2 = (Graph*)malloc(sizeof(Graph));
	if(!g2)
	{
		printf("Out of memory!\n");
		exit(1);
	}

	memcpy(g2, g, sizeof(Graph));
	g2->graph = malloc(sizeof(int)*g->size*g->size);
	if(!g2->graph)
	{
		printf("Out of memory!\n");
		exit(1);
	}
	memcpy(g2->graph, g->graph, sizeof(int)*g->size*g->size);
	return g2;
}

/**************************************************************************
 * GraphGetAdj
 *
 * Get the adjacency of x to y
**************************************************************************/
int GraphGetAdj(Graph *g, int p, int q)
{
	if(!g)
	{
		fprintf(stderr, "No graph!\n");
		return -1;
	}

	if(p < 0 || p >= g->size)
	{
		fprintf(stderr, "Invalid vertex (%d)\n", p);
		return -1;
	}

	if(q < 0 || q >= g->size)
	{
		fprintf(stderr, "Invalid vertex (%d)\n", q);
		return -1;
	}
	return g->graph[g->size*p + q];
}

/**************************************************************************
 * GraphGetAdj
 *
 * Get the adjacency of x to y
**************************************************************************/
void GraphSetAdj(Graph *g, int p, int q, int val)
{
	if(!g)
	{
		fprintf(stderr, "No graph!\n");
		return;
	}

	if(p < 0 || p >= g->size)
	{
		fprintf(stderr, "Invalid vertex (%d)\n", p);
		return;
	}

	if(q < 0 || q >= g->size)
	{
		fprintf(stderr, "Invalid vertex (%d)\n", q);
		return;
	}
	g->graph[g->size*p + q] = val;
}


/**************************************************************************
 * GraphPrint
 *
 * Print a graph
**************************************************************************/
void GraphPrint(Graph *g)
{
	int i,j;

	printf("    |");
	for(i=0; i<g->size; i++)
	{
		printf("%3d ", i);
	}
	printf("\n----+");
	for(i=0; i<g->size; i++)
	{
		printf("----");
	}
	printf("\n");
	for(i=0; i<g->size; i++)
	{
		printf("%3d |", i);
		for(j=0; j<g->size; j++)
		{
			printf("%3d ", GraphGetAdj(g, i, j));
		}
		printf("\n");
	}
}

/**************************************************************************
 * GraphPrintNames
 *
 * Print the vertex names
**************************************************************************/
void GraphPrintNames(Graph *g)
{
	int i;
	printf("%8s | %s\n", "number", "name");
	printf("---------+-----------------\n");
	for(i=0; i<g->size; i++)
	{
		printf("%8d | %s\n", i, g->vertexNames[i]);
	}
}

/**************************************************************************
 * GraphDelete
 *
 *************************************************************************/
 void GraphDelete(Graph *g)
 {
	if(g)
	{
		if(g->graph)
			free(g->graph);
		free(g);
	}
 }


